//    Copyright (C) Kherty.  All rights reserved.
using System;
using OpenLS.Core.Serialization;

namespace OpenLS.Spreadsheet
{
    public class TimePeriodFormattingRule : StandardConditionalFormattingRule
    {
        private TimePeriod timePeriod;

        internal override ConditionalFormattingType Type
        {
            get { return ConditionalFormattingType.TimePeriod; }
        }

        public TimePeriod TimePeriod
        {
            get { return timePeriod; }
            set
            {
                timePeriod = value;
                NotifyPropertyChanged("TimePeriod");
            }
        }

        internal override bool Apply(Cell cell)
        {
            {
                return ApplyStyle(cell, AppliesTo(cell));
            }
        }

        protected override void ReadInner2(ReadContext context)
        {
            TimePeriod = context.GetOptionalEnum("timePeriod", TimePeriod.Today);
        }

        internal override void PrepareBeforeWrite(ConditionalFormatting conditionalFormatting, FormatType formatType)
        {
            Cell cell = conditionalFormatting.Range.TopLeftCell;
            switch (TimePeriod)
            {
                case TimePeriod.Today:
                    Formula1 = string.Format("=FLOOR({0},1)=TODAY()", cell.Label);
                    break;
                case TimePeriod.Tomorrow:
                    Formula1 = string.Format("=FLOOR({0},1)=TODAY()+1", cell.Label);
                    break;
                case TimePeriod.Yesterday:
                    Formula1 = string.Format("=FLOOR({0},1)=TODAY()-1", cell.Label);
                    break;
                case TimePeriod.Last7Days:
                    Formula1 = string.Format("=AND(TODAY()-FLOOR({0},1)<=6,FLOOR({0},1)<=TODAY())", cell.Label);
                    break;
                case TimePeriod.LastWeek:
                    Formula1 = string.Format("=AND(TODAY()-ROUNDDOWN({0},0)>=(WEEKDAY(TODAY())),TODAY()-ROUNDDOWN({0},0)<(WEEKDAY(TODAY())+7))", cell.Label);
                    break;
                case TimePeriod.ThisWeek:
                    Formula1 =
                        string.Format("=AND(TODAY()-ROUNDDOWN({0},0)<=WEEKDAY(TODAY())-1,ROUNDDOWN({0},0)-TODAY()<=7-WEEKDAY(TODAY()))", cell.Label);
                    break;
                case TimePeriod.NextWeek:
                    Formula1 =
                        string.Format("=AND(ROUNDDOWN({0},0)-TODAY()>(7-WEEKDAY(TODAY())),ROUNDDOWN({0},0)-TODAY()<(15-WEEKDAY(TODAY())))", cell.Label);
                    break;
                case TimePeriod.LastMonth:
                    Formula1 =
                        string.Format("=AND(MONTH({0})=MONTH(EDATE(TODAY(),0-1)),YEAR({0})=YEAR(EDATE(TODAY(),0-1)))", cell.Label);
                    break;
                case TimePeriod.NextMonth:
                    Formula1 =
                        string.Format("=AND(MONTH({0})=MONTH(EDATE(TODAY(),0+1)),YEAR({0})=YEAR(EDATE(TODAY(),0+1)))", cell.Label);
                    break;
                case TimePeriod.ThisMonth:
                    Formula1 = string.Format("=AND(MONTH({0})=MONTH(TODAY()),YEAR({0})=YEAR(TODAY()))", cell.Label);
                    break;


                default:
                    throw new NotSupportedException();
            }
        }

        internal override void WriteInner2(WriteContext context)
        {
            context.SetOptionalEnum("timePeriod", TimePeriod, TimePeriod.Today);
        }


        private bool AppliesTo(Cell cell)
        {
            DateTime? date = cell.DateValue;
            if (date == null)
                return false;
            DateTime dateValue = date.Value;
            switch (TimePeriod)
            {
                case TimePeriod.Last7Days:
                    int diffDays = -(dateValue - DateTime.Now).Days;
                    return diffDays < 7 && diffDays >= 0;
                case TimePeriod.Today:
                    return dateValue.Date.Equals(DateTime.Today);
                case TimePeriod.Yesterday:
                    return dateValue.Date.Equals(DateTime.Today.AddDays(-1));
                case TimePeriod.Tomorrow:
                    return dateValue.Date.Equals(DateTime.Today.AddDays(1));

                case TimePeriod.ThisMonth:
                    DateTime now = DateTime.Now;
                    return now.Month == dateValue.Month && now.Year == dateValue.Year;
                case TimePeriod.LastMonth:
                    DateTime lastMonth = DateTime.Now.AddMonths(-1);
                    return lastMonth.Month == dateValue.Month && lastMonth.Year == dateValue.Year;
                case TimePeriod.NextMonth:
                    DateTime nextMonth = DateTime.Now.AddMonths(1);
                    return nextMonth.Month == dateValue.Month && nextMonth.Year == dateValue.Year;
                case TimePeriod.ThisWeek:
                    DateTime thisWeek = DateTime.Today;
                    DateTime firstThisWeek = FirstDay(thisWeek);
                    DateTime firstDateValue = FirstDay(dateValue);
                    return firstThisWeek == firstDateValue;
                case TimePeriod.LastWeek:
                    DateTime lastWeek = DateTime.Today;
                    DateTime firstLastWeek = FirstDay(lastWeek).AddDays(-7);
                    DateTime firstDateValue2 = FirstDay(dateValue);
                    return firstLastWeek == firstDateValue2;

                case TimePeriod.NextWeek:
                    DateTime nextWeek = DateTime.Today;
                    DateTime firstNextWeek = FirstDay(nextWeek).AddDays(-7);
                    DateTime firstDateValue3 = FirstDay(dateValue);
                    return firstNextWeek == firstDateValue3;

                default:
                    throw new NotSupportedException();
            }
        }

        private static DateTime FirstDay(DateTime thisWeek)
        {
            var i = (int) thisWeek.DayOfWeek;
            return thisWeek.AddDays(-i);
        }
    }
}